﻿using System;
using System.Collections.Generic;
using System.IO;
using Index;
using Index.Interfaces;
using Index.TokenMap;

namespace IndexTest
{
    public class TokenMapTest : ITest
    {
        public TokenMapTest()
        {
            this.FailureDetails = new List<string>();
        }

        private List<IToken> tokens1;
        private List<IToken> tokens2;
        private List<IToken> tokens3;
        private List<IToken> tokens4;
        private List<IToken> tokens5; 

        #region ITest Members
        
        public bool Execute()
        {
            bool passed = true;

            string indexDirectory = "BIndex";
             
            if(Directory.Exists(indexDirectory))
            {
                string[] files = Directory.GetFiles(indexDirectory, "*" + TokenMap.FileExtension);

                foreach (string file in files)
                {
                    File.Delete(file);
                }
            }
            else
            {
                Directory.CreateDirectory(indexDirectory);
            }

            using (TokenMap tokenMap = new TokenMap())
            {
                tokenMap.Initialize(indexDirectory);

                InitializeData();
                IToken token = new Token() {Text = "aaa"};
                bool found = tokenMap.FindTokenId(ref token);

                if (found)
                {
                    Console.WriteLine("FindTokenId returned true for non existent token");
                    passed = false;
                }

                // adding the first group of tokens: aaa, bbb, ccc
                tokenMap.AddTokens(ref tokens1);

                string[] segments = Directory.GetFiles(indexDirectory, TokenMap.SegmentFileNamePattern);

                if (segments.Length == 0)
                {
                    Console.WriteLine("No segments have been created");
                    passed = false;
                }

                string segment = Path.GetFileName(segments[0]);

                if (segment != ("0000000000-0000000003" + TokenMap.FileExtension))
                {
                    Console.WriteLine("Incorrect segment name: {0}", segments[0]);
                    passed = false;
                }

                token = new Token() {Text = "aaa"};
                found = tokenMap.FindTokenId(ref token);

                if (!found)
                {
                    Console.WriteLine("FindTokenId returned false for previously added token");
                    passed = false;
                }

                // ID of the bbb token must be 2
                token = new Token() {Text = "bbb"};
                found = tokenMap.FindTokenId(ref token);

                if (token.Id != 2)
                {
                    Console.WriteLine("ID of the 'bbb' token must be 2");
                    passed = false;
                }

                // adding the second group of tokens: fff, ddd, bbb
                tokenMap.AddTokens(ref tokens2);

                segments = Directory.GetFiles(indexDirectory, TokenMap.SegmentFileNamePattern);

                if (segments.Length != 2)
                {
                    Console.WriteLine("There must be 2 segments now");
                    passed = false;
                }

                segment = Path.GetFileName(segments[1]);

                if (segment != ("0000000000-0000000005" + TokenMap.FileExtension))
                {
                    Console.WriteLine("Incorrect segment name: {0}", segments[0]);
                    passed = false;
                }

                // ID of the bbb token should not change - it was assigned to 2 originally
                token = new Token() { Text = "bbb" };
                found = tokenMap.FindTokenId(ref token);

                if (token.Id != 2)
                {
                    Console.WriteLine("ID of the 'bbb' token must not change(must be 2)");
                    passed = false;
                }

                tokenMap.MaxSegments = 2;

                // adding the third group of tokens: aaa, hhh, iii
                // now it is supposed to optimize and create a new merged segment of 
                // the second generation
                // old generation segments should be deleted 
                tokenMap.AddTokens(ref tokens3);

                // only one, merged segment should be around: 0000000001-0000000007.tmap
                segments = Directory.GetFiles(indexDirectory, TokenMap.SegmentFileNamePattern);

                if (segments.Length != 1)
                {
                    Console.WriteLine("Only one, new generation segment should remain");
                    passed = false;
                }

                segment = Path.GetFileName(segments[0]);

                if (segment != ("0000000001-0000000007" + TokenMap.FileExtension))
                {
                    Console.WriteLine("Incorrect optimized segment name: {0}", segments[0]);
                    passed = false;
                }


                // testing merging two indexes

                // create index to merge
                string indexToMergeDirectory = "BIndexToMerge";

                if (Directory.Exists(indexToMergeDirectory))
                {
                    string[] files = Directory.GetFiles(indexToMergeDirectory, "*.*");

                    foreach (string file in files)
                    {
                        File.Delete(file);
                    }
                }
                else
                {
                    Directory.CreateDirectory(indexToMergeDirectory);
                }

                using (TokenMap mergeTokenMap = new TokenMap())
                {
                    mergeTokenMap.Initialize(indexToMergeDirectory);

                    mergeTokenMap.AddTokens(ref tokens4);
                    mergeTokenMap.AddTokens(ref tokens5);


                    // merge
                    tokenMap.Merge(indexToMergeDirectory, 2);

                    // check results
                    // only one, merged segment should be around: 0000000002-0000000012.tmap
                    segments = Directory.GetFiles(indexDirectory, TokenMap.SegmentFileNamePattern);

                    if (segments.Length != 1)
                    {
                        Console.WriteLine("Only one, new generation segment should remain");
                        passed = false;
                    }

                    segment = Path.GetFileName(segments[0]);

                    if (segment != ("0000000002-0000000012" + TokenMap.FileExtension))
                    {
                        Console.WriteLine(
                            "Incorrect optimized segment name: {0} - must be: 0000000002-0000000012.tmap", segments[0]);
                        passed = false;
                    }

                }
            }

            return passed;
        }

        public string DisplayName
        {
            get
            {
                return "TokenMap Test";
            }
        }

        public List<string> FailureDetails { get; set; }

        #endregion

        private void InitializeData()
        {
            tokens1 = new List<IToken>()
                        {
                            new Token()
                                {
                                    Text = "ccc"
                                },
                            new Token()
                                {
                                    Text = "aaa"
                                },
                            new Token()
                                {
                                    Text = "bbb"
                                }
                        };

            tokens2 = new List<IToken>()
                        {
                            new Token()
                                {
                                    Text = "fff"
                                },
                            new Token()
                                {
                                    Text = "ddd"
                                },
                            new Token()
                                {
                                    Text = "bbb"
                                }
                        };
            tokens3 = new List<IToken>()
                        {
                            new Token()
                                {
                                    Text = "aaa"
                                },
                            new Token()
                                {
                                    Text = "iii"
                                },
                            new Token()
                                {
                                    Text = "hhh"
                                }
                        };
            tokens4 = new List<IToken>()
                        {
                            new Token()
                                {
                                    Text = "qqq"
                                },
                            new Token()
                                {
                                    Text = "ccc"
                                },
                            new Token()
                                {
                                    Text = "ppp"
                                }
                        };
            tokens5 = new List<IToken>()
                        {
                            new Token()
                                {
                                    Text = "ttt"
                                },
                            new Token()
                                {
                                    Text = "rrr"
                                },
                            new Token()
                                {
                                    Text = "sss"
                                }
                        };
        }
    }
}